package com.qst.rongxiaotong.interceptor;

import com.qst.rongxiaotong.context.BaseContext;
import com.qst.rongxiaotong.properties.JwtProperties;
import com.qst.rongxiaotong.utils.JwtClaimsConstant;
import com.qst.rongxiaotong.utils.JwtUtil;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;

/**
 * jwt令牌校验的拦截器
 * 此拦截器用于在每次请求时对 JWT 令牌进行校验，确保请求来自合法用户。
 */
@Component // 将该类注册为 Spring 容器中的组件
@Slf4j     // 通过 lombok 自动生成日志对象，用于打印日志信息
public class JwtTokenAdminInterceptor implements HandlerInterceptor {

    @Autowired // 自动注入配置类 JwtProperties，用于获取 JWT 相关配置，如令牌名称、密钥等
    private JwtProperties jwtProperties;

    /**
     * 校验 JWT 令牌
     *
     * @param request  代表当前的 HTTP 请求对象
     * @param response 代表当前的 HTTP 响应对象
     * @param handler  处理器对象，表示当前处理请求的控制器方法
     * @return boolean 如果返回 true 表示请求继续处理，返回 false 表示拦截请求
     * @throws Exception 在校验过程中发生错误时抛出的异常
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 判断当前请求是否为 Controller 的方法（动态资源），如果不是，则直接放行（如静态资源请求）
        if (!(handler instanceof HandlerMethod)) {

            return true;
        }
        log.info("请求路径是控制器方法:{}", request.getRequestURI());
        // 1. 从请求头中获取令牌，令牌名称从配置文件中获取（jwtProperties.getAdminTokenName()）
        String token = request.getHeader(jwtProperties.getAdminTokenName());
        log.info("从请求头获取到的 JWT 令牌: {}", token);

        // 2. 校验令牌是否合法
        try {
            if (token == null || token.isEmpty()) {
                log.warn("JWT 令牌为空，无法进行校验");
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                return false;  // 拦截请求
            }

            log.info("开始校验 JWT 令牌: {}", token);  // 记录令牌的日志信息以便调试

            // 调用 JwtUtil 工具类解析 JWT 令牌，传入密钥（jwtProperties.getAdminSecretKey()）和令牌
            Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);

            // 从令牌的载荷中提取出员工ID（empId），并转换为 Long 类型
            String userName = (String) claims.get(JwtClaimsConstant.USER_NAME);
            log.info("当前员工id：{}", userName); // 打印员工ID日志

            // 将当前的员工ID设置到 BaseContext 中，供后续业务逻辑使用
            BaseContext.setCurrentuserName(userName);

            // 3. 校验成功，放行请求
            log.info("JWT 校验通过，员工ID: {}，请求继续", userName);
            return true;
        } catch (Exception ex) {
            // 4. 校验失败，响应 401 状态码，表示未经授权
            log.error("JWT 校验失败: {}", ex.getMessage());
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return false;  // 拦截请求
        }
    }
}
